/*******************************************************************
*    Desc: RGBA CColor4 structure, using floats
******************************************************************/

#ifndef _ARK_CColor4_H_
#define _ARK_CColor4_H_

#include "ArkBaseMath.h"
#include "CColor3.h"

#pragma warning(disable : 4201)

namespace ArkCommon
{
	namespace Math
	{
		struct CColor4
		{
			union {
				struct 
				{
					float r, g, b, a; // Red, Green, and Blue color data
				};
				float c[4];
			};

			CColor4(){}

			CColor4( float inR, float inG, float inB, float inA ) :
			r( inR ), g( inG ), b( inB ), a( inA )
			{
			}

			CColor4( const CColor3& in, float alpha = 1.f )
			{
				r = in.r;
				g = in.g;
				b = in.b;
				a = alpha;
			}

			CColor4( unsigned long color )
			{
				b = (float)(color&255) / 255.f;
				color >>= 8;
				g = (float)(color&255) / 255.f;
				color >>= 8;
				r = (float)(color&255) / 255.f;
				color >>= 8;
				a = (float)(color&255) / 255.f;
			}


			void Assign( float inR, float inG, float inB, float inA )
			{
				r = inR;
				g = inG;
				b = inB;
				a = inA;
			}

			unsigned long MakeDWord()
			{
				unsigned long iA = (int)(a * 255.f ) << 24;
				unsigned long iR = (int)(r * 255.f ) << 16;
				unsigned long iG = (int)(g * 255.f ) << 8;
				unsigned long iB = (int)(b * 255.f );
				return iA | iR | iG | iB;
			}

			unsigned long MakeDWordSafe()
			{
				CColor4 temp = *this;
				temp.Sat();
				return temp.MakeDWord();
			}

			// if any of the values are >1, cap them.
			void Sat()
			{
				if( r > 1 ) 
					r = 1.f;
				if( g > 1 ) 
					g = 1.f;
				if( b > 1 ) 
					b = 1.f;
				if( a > 1 ) 
					a = 1.f;
				if( r < 0 ) 
					r = 0.f;
				if( g < 0 ) 
					g = 0.f;
				if( b < 0 ) 
					b = 0.f;
				if( a < 0 ) 
					a = 0.f;
			}

			CColor4& operator += ( const CColor4& in );
			CColor4& operator -= ( const CColor4& in );
			CColor4& operator *= ( const CColor4& in );
			CColor4& operator /= ( const CColor4& in );
			CColor4& operator *= ( const float& in );
			CColor4& operator /= ( const float& in );

			// some basic colors.
			static const CColor4 Black;
			static const CColor4 Gray;
			static const CColor4 White;
			static const CColor4 Red;
			static const CColor4 Green;
			static const CColor4 Blue;
			static const CColor4 Magenta;
			static const CColor4 Cyan;
			static const CColor4 Yellow;

		};


		//==========--------------------------  CColor4 Operators


		/**
		* Accumulative addition of two colors
		*/
		inline CColor4& CColor4::operator += ( const CColor4& in )
		{
			r += in.r;   
			g += in.g;   
			b += in.b;
			a += in.a;
			return *this;
		}


		/**
		* Accumulative subtraction of two colors
		*/
		inline CColor4& CColor4::operator -= ( const CColor4& in )
		{
			r -= in.r;   
			g -= in.g;   
			b -= in.b;
			a -= in.a;
			return *this;
		}


		/**
		* Accumulative multiplication of a color by a color
		*/
		inline CColor4& CColor4::operator *= ( const CColor4& in )
		{
			r *= in.r;   
			g *= in.g;   
			b *= in.b;
			a *= in.a;
			return *this;
		}


		/**
		* Accumulative division of a color by a color
		*/
		inline CColor4& CColor4::operator /= ( const CColor4& in )
		{
			r /= in.r;   
			g /= in.g;   
			b /= in.b;
			a /= in.a;
			return *this;
		}


		/**
		* Accumulative multiplication of a color by a scalar
		*/
		inline CColor4& CColor4::operator *= ( const float& in )
		{
			r *= in;   
			g *= in;   
			b *= in;
			a *= in;
			return *this;
		}


		/**
		* Accumulative division of a color by a scalar
		*/
		inline CColor4& CColor4::operator /= ( const float& in )
		{
			float inv = 1.f / in;
			r *= inv;   
			g *= inv;   
			b *= inv;
			a *= inv;
			return *this;
		}


		/**
		* Adds two colors together: ret = a + b
		*/
		inline CColor4 operator+(CColor4 const &a, CColor4 const &b)
		{
			return CColor4
				(
				a.r+b.r,
				a.g+b.g,
				a.b+b.b,
				a.a+b.a
				);
		}; 


		/**
		* Subtracts two colors : ret = a - b
		*/
		inline CColor4 operator-(CColor4 const &a, CColor4 const &b)
		{
			return CColor4
				(
				a.r-b.r,
				a.g-b.g,
				a.b-b.b,
				a.a-b.a
				);
		}; 


		/**
		* Scales a color by a float : ret = a * b
		*/
		inline CColor4 operator*(CColor4 const &a, float const &b)
		{
			return CColor4
				(
				a.r*b,
				a.g*b,
				a.b*b,
				a.a*b
				);
		}; 


		/**
		* Scales a color by a float : ret = a * b
		*/
		inline CColor4 operator*(float  const &a, CColor4 const &b)
		{
			return CColor4
				(
				a*b.r,
				a*b.g,
				a*b.b,
				a*b.a
				);
		}; 


		/**
		* Divides a color by a float : ret = a / b
		*/
		inline CColor4 operator/(CColor4 const &a, float const &b)
		{
			float inv = 1.f / b;
			return CColor4
				(
				a.r*inv,
				a.g*inv,
				a.b*inv,
				a.a*inv
				);
		}; 

		/**
		* Divides a color by a color (piecewise): ret = a / b
		*/
		inline CColor4 operator/(CColor4 const &a, CColor4 const &b)
		{
			return CColor4
				(
				a.r / b.r,
				a.g / b.g,
				a.b / b.b,
				a.a / b.a
				);
		}; 

		/**
		* Multiplies a color by a color (piecewise): ret = a / b
		*/
		inline CColor4 operator*(CColor4 const &a, CColor4 const &b)
		{
			return CColor4
				(
				a.r * b.r,
				a.g * b.g,
				a.b * b.b,
				a.a * b.a
				);
		}; 


		/**
		* color Equality, epsilon used due to numerical imprecision
		*/
		inline bool operator==(CColor4 const &a, CColor4 const &b)
		{
			if(fabs(a.r-b.r)<MATH_EPSILON)
				if(fabs(a.g-b.g)<MATH_EPSILON)
					if(fabs(a.b-b.b)<MATH_EPSILON)
						if(fabs(a.a-b.a)<MATH_EPSILON)
							return true;
			return false;
		};


		#define COLOR4_BLACK	CColor4( 0.f,0.f,0.f, 1.0f)
		#define COLOR4_Gray		CColor4( 0.5f,0.5f,0.5f, 1.0f )
		#define COLOR4_White	CColor4( 1.f,1.f,1.f, 1.0f )
		#define COLOR4_Red		CColor4( 1.f,0.f,0.f, 1.0f )
		#define COLOR4_Green	CColor4( 0.f,1.f,0.f, 1.0f )
		#define COLOR4_Blue		CColor4( 0.f,0.f,1.f, 1.0f )
		#define COLOR4_Magenta	CColor4( 1.f,0.f,1.f, 1.0f )
		#define COLOR4_Cyan		CColor4( 0.f,1.f,1.f, 1.0f )
		#define COLOR4_Yellow	CColor4( 1.f,1.f,0.f, 1.0f )

	}// end of namespace Math
}// end of namespace ArkCommon

using namespace ArkCommon::Math;

#endif //_CColor4_H